package com.tengits.mqttmonitor.rnlibs.rs;

import android.serialport.SerialPort;
import android.text.TextUtils;
import android.util.Log;

import androidx.annotation.Nullable;

import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.modules.core.DeviceEventManagerModule;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


public class SerialPortWrapper extends SerialPortBase{
    private SerialPort serialPort;

    private OutputStream out;
    private InputStream in;
    private Thread readThread;
    private Thread writeThread;

    // private Thread eventThread;
    // Queue<WritableMap> eventQueue = new LinkedList<WritableMap>();
    // Object mEventSemaphore = new Object();

    private AtomicBoolean recvFlag = new AtomicBoolean(false);
    Queue<String> queue = new LinkedList<String>();
    Object mByteSendSemaphore = new Object();
    Object mByteRecvSemaphore = new Object();
    //private final Lock lock =new ReentrantLock();


    private AtomicBoolean closed = new AtomicBoolean(false);

    public SerialPortWrapper(ReactContext reactContext, final String key, int baudRate, int parity, int dataBits, int stopBits) throws IOException{
        super(reactContext, key, baudRate, parity, dataBits, stopBits);

        this.serialPort = SerialPort.newBuilder(key, baudRate)
                .parity(parity)
                .dataBits(dataBits)
                .stopBits(stopBits)
                .build();

        this.out = this.serialPort.getOutputStream();
        this.in = this.serialPort.getInputStream();

        this.readThread = new Thread(new Runnable() {
            @Override
            public void run() {
                while (!closed.get()) {
                    try {
                        if (in == null) return;
                        byte[] buffer = null;
                        String jsBuffer = "";
                        int buffLen = in.available();
                        while (buffLen != 0) {
                            // 初始化byte数组为buffer中数据的长度
                            buffer = new byte[buffLen];
                            in.read(buffer);
                            jsBuffer += bytesToHex(buffer);
                            buffLen = in.available();
                        }
                        if(!TextUtils.isEmpty(jsBuffer)) {
                            WritableMap event = Arguments.createMap();
                            event.putString("data", jsBuffer);
                            event.putString("key", key);
                            event.putString("type", "receive");
                            sendEvent(DataReceivedEvent, event);
                            //Thread.sleep(100);
                            // pushEvent(event);
                            Log.i("serialport", "recv " + jsBuffer);
                            // synchronized (mByteRecvSemaphore) {
                            //     mByteRecvSemaphore.notify();
                            // }
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                        return;
                    }
                }
            }
        });
        this.readThread.start();

        this.writeThread = new Thread(new Runnable() {
            @Override
            public void run() {
                while (!closed.get()) {
                    // synchronized (mByteSendSemaphore) {
                        try {
                            // mByteSendSemaphore.wait();
                            String str2Send;
                            // while((str2Send = queue.poll()) != null) {
                            while(true) {
                                synchronized (mByteSendSemaphore) {
                                    str2Send = queue.poll();
                                }
                                if(str2Send == null){
                                    break;
                                }
                                byte[] buffer = hexStringToByteArray(str2Send);
                                out.write(buffer);
                                out.flush();
                                Log.i("serialport", "send " + str2Send);
                                recvFlag.set(false);
                                // Thread.sleep(msgInterval);
                                // synchronized (mByteRecvSemaphore) {
                                //     mByteRecvSemaphore.wait(READ_WAIT_MILLIS);
                                // }
                            }
                            Thread.sleep(100);
                        } catch (Exception e) {
                            e.printStackTrace();
                            return;
                        }
                    }
                }
        });
        this.writeThread.start();
    }

    @Override
    public void writeHex(String buffer) throws IOException{
        try{
            synchronized (mByteSendSemaphore) {
                this.queue.offer(buffer);
                mByteSendSemaphore.notify();
            }
        }catch (Exception e) {
            e.printStackTrace();
            return;
        }
        // this.out.write(buffer);
        // this.out.flush();
    }

    @Override
    public boolean close(boolean isForce) {
        closed.set(true);
        try {
            in.close();
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        if(serialPort != null) {
            serialPort.close();
            serialPort = null;
        }
        Log.i("serialport", "close " + this.key);
        return true;
    }

    @Override
    public boolean isRunning() {
        return true;
    }

    // void pushEvent(WritableMap event){
    //     synchronized (mEventSemaphore) {
    //         Log.i("serialport", "event: " + event.getString("data"));
    //         this.eventQueue.offer(event);
    //     }
    // }
}
